package com.smartandroid.sa.tag.nodes;

import java.util.ArrayList;
import java.util.List;

import com.smartandroid.sa.tag.Connection;
import com.smartandroid.sa.tag.SmartTag;
import com.smartandroid.sa.tag.helper.HttpConnection;
import com.smartandroid.sa.tag.helper.Validate;
import com.smartandroid.sa.tag.parser.Tag;
import com.smartandroid.sa.tag.select.Elements;

/**
 * A HTML Form Element provides ready access to the form fields/controls that
 * are associated with it. It also allows a form to easily be submitted.
 */
public class FormElement extends Element {
	private final Elements elements = new Elements();

	/**
	 * Create a new, standalone form element.
	 * 
	 * @param tag
	 *            tag of this element
	 * @param baseUri
	 *            the base URI
	 * @param attributes
	 *            initial attributes
	 */
	public FormElement(Tag tag, String baseUri, Attributes attributes) {
		super(tag, baseUri, attributes);
	}

	/**
	 * Get the list of form control elements associated with this form.
	 * 
	 * @return form controls associated with this element.
	 */
	public Elements elements() {
		return elements;
	}

	/**
	 * Add a form control element to this form.
	 * 
	 * @param element
	 *            form control to add
	 * @return this form element, for chaining
	 */
	public FormElement addElement(Element element) {
		elements.add(element);
		return this;
	}

	/**
	 * Prepare to submit this form. A Connection object is created with the
	 * request set up from the form values. You can then set up other options
	 * (like user-agent, timeout, cookies), then execute it.
	 * 
	 * @return a connection prepared from the values of this form.
	 * @throws IllegalArgumentException
	 *             if the form's absolute action URL cannot be determined. Make
	 *             sure you pass the document's base URI when parsing.
	 */
	public Connection submit() {
		String action = hasAttr("action") ? absUrl("action") : baseUri();
		Validate.notEmpty(
				action,
				"Could not determine a form action URL for submit. Ensure you set a base URI when parsing.");
		Connection.Method method = attr("method").toUpperCase().equals("POST") ? Connection.Method.POST
				: Connection.Method.GET;

		Connection con = SmartTag.connect(action).data(formData()).method(method);

		return con;
	}

	/**
	 * Get the data that this form submits. The returned list is a copy of the
	 * data, and changes to the contents of the list will not be reflected in
	 * the DOM.
	 * 
	 * @return a list of key vals
	 */
	public List<Connection.KeyVal> formData() {
		ArrayList<Connection.KeyVal> data = new ArrayList<Connection.KeyVal>();

		// iterate the form control elements and accumulate their values
		for (Element el : elements) {
			if (!el.tag().isFormSubmittable())
				continue; // contents are form listable, superset of submitable
			String name = el.attr("name");
			if (name.length() == 0)
				continue;

			if ("select".equals(el.tagName())) {
				Elements options = el.select("option[selected]");
				for (Element option : options) {
					data.add(HttpConnection.KeyVal.create(name, option.val()));
				}
			} else {
				data.add(HttpConnection.KeyVal.create(name, el.val()));
			}
		}
		return data;
	}

	@Override
	public boolean equals(Object o) {
		return super.equals(o);
	}
}
